import { Component } from './Component';
import { EntityNode } from './EntityNode';

export interface IBasePerformanceData {
  /**
   * 组件实例，表示被监控的组件。
   */
  component: Component;

  /**
   * 最近几次执行时间的历史记录，用于分析短期性能趋势。
   */
  recentExecutionTimes: number[];

  /**
   * 平均执行时间（通常为毫秒值）。
   */
  averageExecutionTime: number;

  /**
   * 最小执行时间（通常为毫秒值）。
   */
  minExecutionTime: number;

  /**
   * 最大执行时间（通常为毫秒值）。
   */
  maxExecutionTime: number;

  /**
   * 性能警告计数，表示该组件触发性能警告的次数。
   */
  warningCount: number;

  /**
   * 性能趋势描述，表示当前性能的变化趋势（如稳定、改善或下降）。
   */
  performanceTrend: string;

  /**
   * 标准差（通常为毫秒值）。
   */
  standardDeviation: number;
}

export interface IonPerformanceData extends IBasePerformanceData {
  /**
   * 实体节点，表示与性能监控相关的实体节点实例。
   */
  entityNode: EntityNode;

  /**
   * 执行时间，表示某个操作或过程的执行时间。
   */
  executionTime: number;

  /**
   * 当前帧率（通常为每秒帧数，FPS）。
   */
  currentFPS: number;
}

/**
 * 性能监控类：负责管理组件的性能数据收集和分析
 */
export class PerformanceMonitor {
  static readonly TARGET_FPS = 60;
  static readonly FRAME_TIME_THRESHOLD = 1000 / this.TARGET_FPS; // ≈ 16.67ms
  static readonly MAX_HISTORY_SIZE = 200; // 增加历史数据容量以提高分析精度
  static readonly PERFORMANCE_TREND_THRESHOLD = 0.15; // 调整性能趋势阈值以提高准确性
  static readonly SAMPLING_INTERVAL = 100; // 性能数据采样间隔（毫秒）
  static isMonitoringEnabled: boolean = true; // 全局监控开关，默认开启

  performanceData: Map<
    string,
    {
      id: string;
      times: number[];
      average: number;
      min: number;
      max: number;
      warningCount: number;
      lastWarningTime: number;
      lastUpdateTime: number;
      standardDeviation: number;
    }
  > = new Map();
  static onPerformanceWarning:
    | ((event: IonPerformanceData) => void)
    | undefined;

  private calculateStandardDeviation(times: number[], mean: number): number {
    if (times.length < 2) {
      return 0;
    }
    const variance =
      times.reduce((acc, val) => acc + Math.pow(val - mean, 2), 0) /
      (times.length - 1);
    return Math.sqrt(variance);
  }

  private compressPerformanceData(times: number[]): number[] {
    if (times.length <= PerformanceMonitor.MAX_HISTORY_SIZE) {
      return times;
    }
    const compressionFactor = Math.ceil(
      times.length / PerformanceMonitor.MAX_HISTORY_SIZE
    );
    const compressed: number[] = [];
    for (let i = 0; i < times.length; i += compressionFactor) {
      const chunk = times.slice(i, i + compressionFactor);
      // 使用加权平均，最新的数据权重更高
      const weightedSum = chunk.reduce((acc, val, idx) => {
        const weight = (idx + 1) / chunk.length;
        return acc + val * weight;
      }, 0);
      compressed.push(weightedSum / ((chunk.length + 1) / 2));
    }
    return compressed;
  }

  private cleanupOldData(perfData: any): void {
    const now = Date.now();
    if (now - perfData.lastCleanupTime < PerformanceMonitor.SAMPLING_INTERVAL) {
      return;
    } // 根据采样间隔控制数据清理频率

    if (perfData.times.length > PerformanceMonitor.MAX_HISTORY_SIZE) {
      perfData.times = this.compressPerformanceData(perfData.times);
      perfData.compressionRatio =
        perfData.times.length / PerformanceMonitor.MAX_HISTORY_SIZE;
    }

    perfData.lastCleanupTime = now;
  }

  private shouldTriggerWarning(executionTime: number): boolean {
    return executionTime > PerformanceMonitor.FRAME_TIME_THRESHOLD;
  }

  recordComponentPerformance(
    entityNode: EntityNode,
    component: Component,
    startTime: number,
    endTime: number
  ) {
    if (!PerformanceMonitor.isMonitoringEnabled) {
      return;
    }
    const executionTime = endTime - startTime;
    const componentName = component.constructor.name;
    const perfData = this.performanceData.get(componentName) || {
      id: entityNode.uuid,
      times: [],
      average: 0,
      min: Infinity,
      max: -Infinity,
      warningCount: 0,
      lastWarningTime: 0,
      standardDeviation: 0,

      lastUpdateTime: Date.now(),
    };

    perfData.average =
      perfData.times.reduce((a, b) => a + b, 0) / perfData.times.length;
    perfData.min = Math.min(perfData.min, executionTime);
    perfData.max = Math.max(perfData.max, executionTime);
    perfData.standardDeviation = this.calculateStandardDeviation(
      perfData.times,
      perfData.average
    );

    this.cleanupOldData(perfData);

    this.performanceData.set(component.constructor.name, perfData);

    // 性能警告逻辑
    // 限制历史数据数量
    if (perfData.times.length >= PerformanceMonitor.MAX_HISTORY_SIZE) {
      perfData.times.shift();
    }
    perfData.times.push(executionTime);

    const fps = 1000 / executionTime;
    const now = Date.now();
    perfData.lastWarningTime = now;
    const trend = this._calculatePerformanceTrend(perfData.times);

    if (this.shouldTriggerWarning(executionTime)) {
      perfData.warningCount++;
    }

    PerformanceMonitor.onPerformanceWarning?.call(this, {
      entityNode,
      component,
      executionTime: Number(executionTime.toFixed(2)),
      recentExecutionTimes: perfData.times.slice(-10),
      averageExecutionTime: Number(perfData.average.toFixed(2)),
      minExecutionTime: Number(perfData.min.toFixed(2)),
      maxExecutionTime: Number(perfData.max.toFixed(2)),
      standardDeviation: Number(perfData.standardDeviation.toFixed(2)),
      warningCount: perfData.warningCount,
      performanceTrend: trend,
      currentFPS: Number(fps.toFixed(1)),
    });
  }

  /**
   * 获取指定组件的性能数据
   * @param component - 组件实例
   *  @param name - 组件名称
   * @returns 组件的性能数据，如果组件不存在则返回null
   */
  getComponentPerformance(
    component: Component,
    name: string
  ): IBasePerformanceData | null {
    const perfData = this.performanceData.get(name);
    if (!perfData) {
      console.warn(`组件 ${name} 的性能数据未找到。`);
      return null;
    }

    const recentTimes = perfData.times.slice(-20);
    const trend = this._calculatePerformanceTrend(recentTimes);

    perfData.standardDeviation = this.calculateStandardDeviation(
      perfData.times,
      perfData.average
    );

    return {
      component,
      recentExecutionTimes: recentTimes,
      averageExecutionTime: Number(perfData.average.toFixed(2)),
      minExecutionTime: Number(perfData.min.toFixed(2)),
      maxExecutionTime: Number(perfData.max.toFixed(2)),
      warningCount: perfData.warningCount,
      standardDeviation: Number(perfData.standardDeviation.toFixed(2)),
      performanceTrend: trend,
    } as IBasePerformanceData;
  }

  private _calculatePerformanceTrend(times: number[]): string {
    if (times.length < 2) {
      return '稳定';
    }

    const recentTimes = times.slice(-20);
    const firstHalf = recentTimes.slice(0, Math.floor(recentTimes.length / 2));
    const secondHalf = recentTimes.slice(Math.floor(recentTimes.length / 2));

    const firstHalfAvg =
      firstHalf.reduce((a, b) => a + b, 0) / firstHalf.length;
    const secondHalfAvg =
      secondHalf.reduce((a, b) => a + b, 0) / secondHalf.length;

    // 计算标准差以评估波动性
    const firstStdDev = this.calculateStandardDeviation(
      firstHalf,
      firstHalfAvg
    );
    const secondStdDev = this.calculateStandardDeviation(
      secondHalf,
      secondHalfAvg
    );

    const changePercent = ((secondHalfAvg - firstHalfAvg) / firstHalfAvg) * 100;
    const volatilityChange = ((secondStdDev - firstStdDev) / firstStdDev) * 100;

    // 综合考虑平均值变化和波动性变化
    if (
      Math.abs(changePercent) <
        PerformanceMonitor.PERFORMANCE_TREND_THRESHOLD &&
      Math.abs(volatilityChange) < 20
    ) {
      return '稳定';
    } else if (changePercent > PerformanceMonitor.PERFORMANCE_TREND_THRESHOLD) {
      return volatilityChange > 20 ? '严重下降' : '下降';
    } else if (
      changePercent < -PerformanceMonitor.PERFORMANCE_TREND_THRESHOLD
    ) {
      return volatilityChange < -20 ? '显著改善' : '改善';
    } else if (volatilityChange > 20) {
      return '波动增大';
    } else if (volatilityChange < -20) {
      return '波动减小';
    }
    return '稳定';
  }
}
